/*  File name: BufferedMcBSP0TxRx.c 
    
    Buffered interrupt support for McBSP0 Tx and Rx.
    Requires clocking to be done by the FPGA.
    Single 16-bit values transferred.
    Transfers are timed by received data.
    Designed for continuous flow.
    Very basic.  Buffer size is hard coded.
    Self contained.
   
    04Dec2007 .. initial version .. KMetzger
    
*/    

#define DRR2_0  *((ioport unsigned *)0x2800)
#define DRR1_0  *((ioport unsigned *)0x2801)
#define DXR2_0  *((ioport unsigned *)0x2802)
#define DXR1_0  *((ioport unsigned *)0x2803)
#define SPCR2_0 *((ioport unsigned *)0x2804)
#define SPCR1_0 *((ioport unsigned *)0x2805)
#define RCR2_0  *((ioport unsigned *)0x2806)
#define RCR1_0  *((ioport unsigned *)0x2807)
#define XCR2_0  *((ioport unsigned *)0x2808)
#define XCR1_0  *((ioport unsigned *)0x2809)
#define SRGR2_0 *((ioport unsigned *)0x280A)
#define SRGR1_0 *((ioport unsigned *)0x280B)
#define MCR2_0  *((ioport unsigned *)0x280C)
#define MCR1_0  *((ioport unsigned *)0x280D)
#define PCR_0   *((ioport unsigned *)0x2812)

int volatile Flag;

#define IER0 ((unsigned long)0x00)
#define IFR0 ((unsigned long)0x01)
#define IVPD ((unsigned long)0x49)
#define IVPH ((unsigned long)0x4A)

#define RINT (0x28>>1)
#define RINT_BIT 0x0020

void resetv();
interrupt void McBSP0int(void);
static void setup_McBSP0loop16(void);

#define RBufferSize 70
static unsigned int RBuffer[RBufferSize];
volatile unsigned R0BufferCounter;
static unsigned int *RGet, *RPut;

#define XBufferSize 70  
static unsigned int XBuffer[XBufferSize];
volatile unsigned X0BufferCounter;
static unsigned int *XGet, *XPut;

void setup_buffered_McBSP0(void)
{
    long resetloc;
    
    // set up interrupt vector and interrupt registers

	setup_McBSP0loop16();
    resetloc = (long)resetv;
    far_poke(IVPD, (unsigned)(resetloc>>8));
    far_poke(IVPH, (unsigned)(resetloc>>8));
    far_poke((resetloc>>1)+RINT,   (unsigned)((unsigned long)McBSP0int>>16));
    far_poke((resetloc>>1)+RINT+1, (unsigned)((unsigned long)McBSP0int));
    far_poke(IER0, far_peek(IER0)|RINT_BIT);  // enable McBSP Receiver interrupt
    far_poke(IFR0, RINT_BIT);                 // clear the flag
    RGet = RPut = &RBuffer[0];
    R0BufferCounter = 0;
    XGet = XPut = &XBuffer[0];
    X0BufferCounter = 0;
}

void setup_McBSP0loop16(void)
{
    /* set up McBSP port 0 */

    SPCR1_0 = 0x0000;  // stop rcvr
    SPCR2_0 = 0x0000;  // stop xmtr
    RCR1_0  = 0x0040;  // 1 16-bit word 
    RCR2_0  = 0x0000;
    XCR1_0  = 0x0040;  // 1 16-bit word 
    XCR2_0  = 0x0000;
    SRGR1_0 = 0x0000;
    SRGR2_0 = 0x0000;
    MCR1_0  = 0x0000;
    MCR2_0  = 0x0000;
    PCR_0   = 0x0000; // use of clock edges

    SPCR1_0 = 0x0001; // start rcvr
    SPCR2_0 = 0x00C1; // start xmtr
}

//--------- application time

unsigned GetFromMcBSP0(void)
{
    unsigned value;
    
    while (R0BufferCounter == 0);  // wait for a value
    value = *RGet++;
    _disable_interrupts();  // start a critical section
        R0BufferCounter--;
    _enable_interrupts();   // end critical section
    if (RGet >= RBuffer+RBufferSize) RGet = RBuffer;
    return value;
}

void SendToMcBSP0(unsigned value)
{
    while (X0BufferCounter >= XBufferSize); // wait for room
    *XPut++ = value;
    _disable_interrupts();  // start a critical section
        X0BufferCounter++;
    _enable_interrupts();   // end critical section
    if (XPut >= XBuffer+XBufferSize) XPut = XBuffer;
}

//--------- interrupt time

unsigned temp;

interrupt void McBSP0int(void)
{   
    temp = DRR1_0;            
    if (R0BufferCounter < RBufferSize) {
        *RPut++ = temp;
        R0BufferCounter++;
        if (RPut >= RBuffer+RBufferSize) RPut = RBuffer;
    }
    DXR1_0 = *XGet;
    //DXR1_0 = temp;
    if (X0BufferCounter != 0) {
        XGet++;
        X0BufferCounter--;
        if (XGet >= XBuffer+XBufferSize) XGet = XBuffer;
    }
}
